package com.analyse.stock.utils;

import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
import org.jfree.chart.ui.ApplicationFrame;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;
import org.ta4j.core.BarSeries;
import org.ta4j.core.BaseBarSeriesBuilder;
import org.ta4j.core.Rule;
import org.ta4j.core.indicators.SMAIndicator;
import org.ta4j.core.indicators.StochasticOscillatorKIndicator;
import org.ta4j.core.rules.CrossedDownIndicatorRule;
import org.ta4j.core.rules.CrossedUpIndicatorRule;

import javax.swing.*;
import java.awt.*;
import java.time.ZonedDateTime;

public class ChartExample extends ApplicationFrame {

    public ChartExample(String title) {
        super(title);

        // 创建时间序列和计算 KD 指标
        BarSeries series = createSeries();
        StochasticOscillatorKIndicator kIndicator = new StochasticOscillatorKIndicator(series, 14); // K 线
        SMAIndicator dIndicator = new SMAIndicator(kIndicator, 3); // D 线

        // 定义买卖信号规则
        Rule buyRule = new CrossedUpIndicatorRule(kIndicator, dIndicator);
        Rule sellRule = new CrossedDownIndicatorRule(kIndicator, dIndicator);

        // 创建图表数据
        XYSeries kSeries = new XYSeries("K 值");
        XYSeries dSeries = new XYSeries("D 值");
        XYSeries buySignals = new XYSeries("买入点");
        XYSeries sellSignals = new XYSeries("卖出点");

        for (int i = 0; i < series.getBarCount(); i++) {
            kSeries.add(i, kIndicator.getValue(i).doubleValue());
            dSeries.add(i, dIndicator.getValue(i).doubleValue());

            // 标注买入点
            if (buyRule.isSatisfied(i)) {
                buySignals.add(i, kIndicator.getValue(i).doubleValue());
            }

            // 标注卖出点
            if (sellRule.isSatisfied(i)) {
                sellSignals.add(i, kIndicator.getValue(i).doubleValue());
            }
        }

        // 构建图表数据集
        XYSeriesCollection dataset = new XYSeriesCollection();
        dataset.addSeries(kSeries);
        dataset.addSeries(dSeries);
        dataset.addSeries(buySignals);
        dataset.addSeries(sellSignals);

        // 创建图表
        JFreeChart chart = ChartFactory.createXYLineChart(
                "KD 指标买卖点图", // 图表标题
                "时间点",         // X 轴标签
                "指标值",         // Y 轴标签
                dataset,          // 数据集
                PlotOrientation.VERTICAL,
                true,             // 显示图例
                true,             // 显示工具提示
                false             // 不生成 URL
        );

        // 自定义图表样式
        XYPlot plot = chart.getXYPlot();
        XYLineAndShapeRenderer renderer = new XYLineAndShapeRenderer();
        renderer.setSeriesPaint(0, Color.BLUE); // K 线颜色
        renderer.setSeriesPaint(1, Color.RED); // D 线颜色
        renderer.setSeriesPaint(2, Color.GREEN); // 买入点颜色
        renderer.setSeriesPaint(3, Color.ORANGE); // 卖出点颜色
        renderer.setSeriesShapesVisible(2, true); // 买入点形状
        renderer.setSeriesShapesVisible(3, true); // 卖出点形状
        plot.setRenderer(renderer);

        // 将图表嵌入面板
        ChartPanel chartPanel = new ChartPanel(chart);
        chartPanel.setPreferredSize(new Dimension(800, 600));
        setContentPane(chartPanel);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> {
            ChartExample example = new ChartExample("KD 指标买卖点");
            example.pack();
            example.setVisible(true);
        });
    }

    /**
     * 创建模拟时间序列
     */
    private static BarSeries createSeries() {
        // 构建时间序列
        BarSeries series = new BaseBarSeriesBuilder().withName("my-Series").build();
        series.addBar(ZonedDateTime.now().minusDays(9), 100.0, 102.0, 99.0, 101.0, 1000.0);
        series.addBar(ZonedDateTime.now().minusDays(8), 101.0, 103.0, 100.0, 102.0, 1200.0);
        series.addBar(ZonedDateTime.now().minusDays(7), 102.0, 104.0, 101.0, 103.0, 1500.0);
        series.addBar(ZonedDateTime.now().minusDays(6), 103.0, 105.0, 102.0, 102.5, 1400.0);
        series.addBar(ZonedDateTime.now().minusDays(5), 102.5, 104.0, 101.0, 101.0, 1300.0);
        series.addBar(ZonedDateTime.now().minusDays(4), 101.0, 102.0, 100.0, 100.5, 1100.0);
        series.addBar(ZonedDateTime.now().minusDays(3), 100.5, 101.0, 99.0, 99.5, 900.0);
        series.addBar(ZonedDateTime.now().minusDays(2), 99.5, 100.0, 98.0, 98.5, 800.0);
        series.addBar(ZonedDateTime.now().minusDays(1), 98.5, 99.0, 97.0, 97.5, 700.0);
        series.addBar(ZonedDateTime.now(), 97.5, 98.0, 96.0, 96.5, 600.0);
        return series;
    }
}
